export function test(vm) {

}

import { getValue ,mergeAttr} from "../util/ObjectUtil.js";


/**
 * 预渲染，建立双向索引：
 *    通过虚拟节点vnode可以里面插值表达式的vue-data-key字符串
 *    通过vue-data-key字符串可以找到对应的vnode结点，从而可以设置节点内容。
 * @param {*} vm 
 * @param {*} vnode 
 * @returns 
 */
export function prepareRender(vm, vnode) {
  if (vnode == null) {
    return;
  } else if (vnode.nodeType === 3) {
    analysisTemplateString(vnode);
  } else if(vnode.nodeType === 0){ //如果是虚拟节点。
    setTemplate2Vnode("{{" + vnode.data + "}}", vnode);
    setVnode2Template("{{" + vnode.data + "}}", vnode);//给虚拟节点加上索引，否则v-for的模板元素就没有索引，无法还原
    for (let i = 0; i < vnode.children.length; i++) {
      prepareRender(vm, vnode.children[i]);
    }
  }else if (vnode.nodeType == 1) {
    analysisAttr(vm, vnode);
    for (let i = 0; i < vnode.children.length; i++) {
      prepareRender(vm, vnode.children[i]);
    }
  }
}

let tempalte2Vnode = new Map();
let Vnode2template = new Map();




//渲染函数，挂载到原型上
export function renderMixin(Due) {
  Due.prototype._render = function () {
    renderNode(this, this._vnode);
  };
}

//根据vue-data-key找到虚拟节点
export function renderData(vm, data) {
  return tempalte2Vnode.get(data);
}

// 建立映射关系，模板和结点间的映射 规范：to -> 2 for->4

/**
 * 生成一个map对象，从map对象中的key可以搜索到节点vnode
 * @param {模板} template
 * @param {所在的文本节点} vnode
 */
function setTemplate2Vnode(template, vnode) {
  let templateName = getTamplateName(template);
  let vnodeSet = tempalte2Vnode.get(templateName); //从map中搜索是否存在key
  //因为一个模板可能对于多个节点，所以传入一个数组
  if (vnodeSet) {
    vnodeSet.push(vnode);
  } else {
    tempalte2Vnode.set(templateName, [vnode]);
  }
}
//同理
function setVnode2Template(template, vnode) {
  let templateSet = Vnode2template.get(vnode);
  let templateName = getTamplateName(template);
  if (templateSet) {
    templateSet.push(templateName);
  } else {
    Vnode2template.set(vnode, [templateName]);
  }
}

/**
 * 解析文本节点的模板字符串部分
 * @param {文本节点} vnode
 */
function analysisTemplateString(vnode) {
  let templateStrList = vnode.text.match(/{{[^{]+}}/g);
  for (let i = 0; templateStrList && i < templateStrList.length; i++) {
    // 建立索引
    setTemplate2Vnode(templateStrList[i], vnode);
    setVnode2Template(templateStrList[i], vnode);
  }
}

/**
 * 去掉模板字符串的双括号
 * @param {模板字符串} template
 */
function getTamplateName(template) {
  return template.substring(2, template.length - 2);
}

export function renderNode(vm, vnode) {
  if (vnode.nodeType == 3) {
    let templates = Vnode2template.get(vnode);
    if (templates) {
      let result = vnode.text; //获取节点的文本
    
      for (let i = 0; i < templates.length; i++) {
        const templateValue = getTemplateValue(
          [vm._data, vnode.env],
          templates[i]
        );
        //获取vue-data-value值,第一个参数数组的第二个值是该节点局部变量，预留的，后面v-for有用。
        result = result.replace("{{" + templates[i] + "}}", templateValue);

        // result = templateValue;
      }

      vnode.elm.nodeValue = result;
    }
  } else if (vnode.nodeType == 1 && vnode.tag == "INPUT") {
    let templates = Vnode2template.get(vnode);
    if (templates) {
      for (let i = 0; i < templates.length; i++) {
        const element = templates[i];
        let value = getTemplateValue([vm._data, vnode.env], element);
        if (value) {
          vnode.elm.value = value;
        }
      }
    }
  } else {
    for (let i = 0; i < vnode.children.length; i++) {
      renderNode(vm, vnode.children[i]);
    }
  }
}

function getTemplateValue(objs, name) {
  //objs是一个数组，数组里面有很多对象，name是key值
  //查找key对应的value，先是全局数据vm._data,再是局部值vnode.env.局部的值有一个继承关系，子节点的更多。
  //重复了后面覆盖前面的。
  let obj = mergeAttr(objs[0],objs[1]);
  let temp = getValue(obj, name); 
  // console.log(temp);

    return temp;


}
export function getVNodeByTemplate(name) {
  //通过key的名字找到对应的节点，该key一定是vue-data中的key，name就是模板字符串去掉双括号后的字符串
  return tempalte2Vnode.get(name);
}

//有些vue-data-key是没有在模板字符串中，而是在属性中，所以对于dom节点的属性也要建立索引
function analysisAttr(vm, vnode) {
  let attrNames = vnode.elm.getAttributeNames();
  if (attrNames.indexOf("v-model") > -1) {
    setTemplate2Vnode("{{" + vnode.elm.getAttribute("v-model") + "}}", vnode);
    setVnode2Template("{{" + vnode.elm.getAttribute("v-model") + "}}", vnode);
  }
}





//重新构造索引，重构索引不会触发dom操作
export function clearMap() {
  tempalte2Vnode.clear();
  Vnode2template.clear();
}